Fibonacci Heap

피보나치 힙(Fibonacci Heap): 루트를 갖는 트리들의 집합
피보나치 힙은 병합 가능한 힙을 만들기 위한 연산을 지원하며, 상수의 분할 상환 시간을 가진다.

- MakeHeap(void)
- Insert(H, x)
- Minimum(H)
- ExtractMin(H)
- Union(H1, H2)
  H1, H2의 원소를 포함하는 힙을 리턴하고, 기존의 힙은 파괴
- DecreaseKey(H, x, k)
- Delete(H, x)

ExtractMin, Delete O(lgn)을 가지고 외는 \Theta(1)의 시간복잡도를 가짐

이론적으로 Delete, ExtractMin이 적은 연산에 대해서 피보나치힙은 매우 효율적으로 동작한다.
데이터의 개수가 아주 많지 않은 경우, 이진 힙이 더 효율적임
Fibonacci Heap Poetential Cost Φ(H)=t(H)+2m(H) t(H): 루트 리스트 트리 개수 m(H): mark==true인 노드 개수
DecreaseKey & Delete는 생략(Node에 대한 포인터로 구현하지 않아 Search를 구현해야 함)
#include <iostream>
#include <cmath>
#include <climits>
using namespace std;
struct Node{
Node *left, *right, *p, *child;
int key, degree;
bool mark;
Node(int _key, bool _mark=false): key(_key), mark(_mark){
left=this; right=this;
p=nullptr; child=nullptr;
degree=0;
}
};
struct FibHeap{
Node* min;
int n;
FibHeap(void){
min=nullptr;
n=0;
}
~FibHeap(){}
int maxDegree(void){
int D=static_cast<int>(log(this->n)/log(2));
return D;
}
void Insert(int key){
Node* x=new Node(key);
if(this->min==nullptr) this->min=x;
else if(this->n==1){
this->min->left=x;
this->min->right=x;
x->left=this->min;
x->right=this->min;
if(x->key<this->min->key) this->min=x;
} else {
Node* oriRight=this->min->right;
oriRight->left=x;
this->min->right=x;
x->left=this->min;
x->right=oriRight;
if(x->key<this->min->key) this->min=x;
}
this->n++;
}
void InsertRoot(Node* x){
Node* origLeft=this->min->left;
this->min->left=x;
x->left=origLeft;
x->right=this->min;
if(this->min->key>x->key) this->min=x;
}
int Minimum(void){
if(this->min==nullptr) return 0;
return this->min->key;
}
void Union(FibHeap* other){
Node* Left=other->min;
Node* Right=other->min->right;
while(Right!=Left){
Right=Right->right;
}
Right=Right->left;
Node* origLeft=this->min->left;
origLeft->right=Left;
Left->left=origLeft;
this->min->left=Right;
Right->right=this->min;
if(this->min->key>other->min->key) this->min=other->min;
this->n+=other->n;
delete other;
}
void Link(Node* y, Node* x){
Node* yLeft=y->left;
Node* yRight=y->right;
y->left->right=yRight;
y->right->left=yLeft;
x->degree++;
if(x->child==nullptr) x->child=y;
else {
Node* origxcr=x->child->right;
y->right=origxcr;
y->left=x->child;
x->child->right=y;
origxcr->left=y;
}
}
void Consolidate(void){
int D=maxDegree();
Node** A=new Node*[D+1];
for(int i=0; i<D; ++i) A[i]=nullptr;
Node* w=this->min;
Node* origw=w;
do{
Node* x=w;
int d=x->degree;
while(A[d]!=nullptr){
Node* y=A[d];
if(x->key>y->key){
Node* tmp=x;
x=y;
y=tmp;
}
Link(y, x);
A[d]=nullptr;
d++;
}
A[d]=x;
w=w->right;
}while(w!=origw);
this->min=nullptr;
for(int i=0; i<=D; ++i){
if(A[i]!=nullptr){
if(this->min==nullptr) this->min=A[i];
else {
if(this->min->key>A[i]->key) this->min=A[i];
}
}
}
delete[] A;
}
void ExtractMin(void){
Node* z=this->min;
if(z!=nullptr){
Node* x=z->child;
if(x!=nullptr){
Node* origx=x;
do{
InsertRoot(x);
x->p=nullptr;
x=x->right;
} while(x!=origx);
}
Node* Left=z->left;
Node* Right=z->right;
Left->right=Right;
Right->left=Left;
if(z==z->right){
this->min=nullptr;
} else {
this->min=z->right;
Consolidate();
}
this->n--;
delete z;
}
}
};
int main(void){
int sz=10;
FibHeap* tree1=new FibHeap();
int* list=new int[sz];
for(int i=0; i<sz; i++){
int rdn=591*i%17+1;
tree1->Insert(rdn);
list[i]=rdn;
if(i%7==6){
tree1->ExtractMin();
std::cout<<"Extract at: "<<rdn<<'['<<i<<']'<<std::endl;
}
std::cout<<tree1->min->key<<std::endl;
}
for(int i=0; i<sz; ++i) std::cout<<list[i]<<' ';
std::cout<<std::endl;
std::cout<<tree1->Minimum()<<std::endl;
return 0;
}
Delete는 아래 두 조합으로 구현할 수 있다.
Delete(H, x):
DecreaseKey(H, x, INT_MIN);
ExtractMin(H);